import { Link } from '@brillout/docpress'

> This page is about handling bugs, expected errors, and network errors.
>
> - To block unauthorized access: <Link href="/permissions" />
> - To handle invalid `<form>` values: <Link href="/form-validation" />
> - To install error tracking: <Link href="/onBug" />


## Bugs

If a telefunction has a bug:

```ts
// hello.telefunc.ts
// Environment: server

export { hello }

async function hello(name: string) {
  // This telefunction has a bug: it should be `name` instead of `namee`
  return 'Hello ' + namee
}
```

Then a telefunction call throws an error:

```html
<!-- index.html -->
<!-- Environment: client -->

<html>
  <body>
    <script type="module">
      import { hello } from './hello.telefunc.js'

      try {
        await hello('Eva')
        console.log("I'm never printed")
      } catch(err) {
        console.log(err.message) // Prints 'Internal Server Error'
        // E.g. show a popup "Something went wrong. Try again (later)."
        // ...
      }
    </script>
  </body>
</html>
```

> To avoid leaking sensitive information, Telefunc doesn't send the original `Error` object to the frontend.


## Expected Errors

An error thrown by a telefunction may not be a bug but an expected error instead.

For example:
 - Some authentication libraries throw an error if the user isn't logged in.
 - Some validation libraries throw errors upon invalid data.

We can:
 1. Propagate the error to the frontend, or
 2. handle the error on the server-side.

<br/>

**1. Propagate the error to the frontend.**

We can propagate error information to the frontend like this:

```ts
import { validate } from 'some-library'

function onFormSubmit(data) {
  try {
    validate(data)
  } catch (err) {
    return {
      errorMessage: `Data is invalid: ${err.message}. Please enter valid data.`
    }
  }
}
```

We can also use `throw Abort(someValue)`:

```ts
import { validate } from 'some-library'
import { Abort } from 'telefunc'

function onFormSubmit(data) {
  try {
    validate(data)
  } catch (err) {
    throw Abort({
      errorMessage: `Data is invalid: ${err.message}. Please enter valid data.`
    })
  }
}
```

In general, we recommend using `return { someValue }` instead of `throw Abort(someValue)`, see explanation at <Link href="/form-validation#throw-abort-somevalue" doNotInferSectionTitle={true} />.

> We need to catch the error and use `throw Abort(someValue)` because Telefunc doesn't send the original `Error` object to the frontend (in order to avoid leaking sensitive information).

Also see <Link href="/permissions#getcontext-wrapping" doNotInferSectionTitle={true} />.

<br/>

**2. Handle the error on the server-side.**

We can handle the thrown error at our Telefunc server middleware:

```ts
// server.ts

// Server (Express.js/Fastify/...)

import { telefunc } from 'telefunc'

// Telefunc middleware
app.all('/_telefunc', async (req: Request, res: Response) => {
  const httpResponse = await telefunc(/* ... */)
  // Telefunc exposes any error thrown by a telefunction at httpResponse.err
  if (httpResponse.err) {
    // Our error handling
  }
})
```

Also see <Link href="/getContext#provide" />.


## Network Errors

If the user's browser can't connect to our server:

```html
<!-- index.html -->
<!-- Environment: client -->

<html>
  <body>
    <script type="module">
      import { hello } from './hello.telefunc.js'

      try {
        await hello('Eva')
      } catch(err) {
        if (err.isConnectionError) {
          // There is a network problem:
          //  - the user isn't connected to the internet, or
          //  - our server is down.
          console.log(err.message) // Prints 'No Server Connection'
        }
      }
    </script>
  </body>
</html>
```
